package p2pcdnsim.network;


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


import desmoj.core.simulator.Model;
import desmoj.core.simulator.SimProcess;
import desmoj.core.simulator.SimTime;

public class LinkControl extends SimProcess {
	
	private static LinkControl control;
	
	static LinkControl getInstance() {
		return control;
	}
	
	public static void createLinkControl(Model owner) {
		control = new LinkControl(owner,"LinkControl",true);
		control.activate(new SimTime(0.0));
	}
	
	List<Event> events = new ArrayList<Event>(); 

	private LinkControl(Model owner, String name, boolean showInTrace) {
		super(owner, name, showInTrace);
	}

	@Override
	public void lifeCycle() {
		while (true) {
			if (events.size() == 0) {
				this.passivate();
			} else {
				Event event = events.remove(0);
				// System.out.println(event.time+"    "+this.currentTime().getTimeValue());
				if (event.time > this.currentTime().getTimeValue()) {
					double hold = event.time - this.currentTime().getTimeValue();
					//System.out.println("Now: "+this.currentTime().getTimeValue());
					// System.out.println("hold "+hold);
					if (this.isScheduled()) {
						// System.out.println("trying to hold but already scheduled at "+this.scheduledAt());
						this.reSchedule(new SimTime(hold));
						this.passivate();
					} else {
						// System.out.println("Now: "+this.currentTime().getTimeValue()+" s:"+this.scheduledAt());
						hold(new SimTime(hold));
						// System.out.println("Now: "+this.currentTime().getTimeValue());
					}
				}
				event.link.processPacket(event.packet);
			}
		}
	}
	
	public synchronized void schedulePacket(Packet packet, Link link, double time) {		
		Event event = new Event();
		event.time = time;
		event.link = link;
		event.packet = packet;
		
		int index = Collections.binarySearch(events, event);
		if(index <0) events.add(-index-1, event);
		else events.add(index,event);

		if(!this.isScheduled()) this.activate(new SimTime(0.0));
	}

	private class Event implements Comparable<Event>{		
		double time;
		Link link;
		Packet packet;
		
		@Override
		public int compareTo(Event o) {
			return new Double(time).compareTo(new Double(o.time));
		}
	}	

}
